/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/* 
 * Copyright (c) 2009 City University of Hong Kong
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License m_version 2 as
 * published by the Free Software Foundation;
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * 
 * Author: Wilson Thong (wilsonwk@ee.cityu.edu.hk) 
 */
#ifndef BMSN_PATH_SELECTOR_TAG_H
#define BMSN_PATH_SELECTOR_TAG_H

#include "ns3/tag.h"
#include "jitter-sim-include.h"
#include <iostream>

namespace ns3 {
namespace eecityu {

using namespace std;

/**
 * \brief Used by BmsnRouting protocol object to select one of the all possible
 * paths between sources and destinations on a BMSN topology.
 *
 * When a packet arrives to a node and is being handled by BmsnRouting Protocol,
 * a BmsnPathSelectorTag is read. If there are multiple feasible exits for the packet 
 * to leave the node, the actual exit used depends on the BmsnPathSelectorTag 
 * value. Using this tag allows exploring multiple paths in a controlled manner.
 * If random number generator is used instead, there will be no mean to specify 
 * an explict path for packets to follow. Or if source routing with 
 * intermiediate nodes being specified explicitly, the path selection logic would 
 * become unnecesarily complex as the logic has to provide a complete path for
 * every packet generated.
 *
 * BmsnPathSelectorTag value is read as a series of bits and the reading starts
 * from the lowest significat bit first. Two lowest significant bits are read
 * from the tag value. These two bits, either 00, 01, 10, or 11, indicates which
 * feasible exit is chosen for the BmsnRouting protocol object. Bits used are 
 * discarded by means of right-shifting the tag value by 2 positions.
 *
 * The highest significant bit of a BmsnPathSelectorTag value will always be set,
 * so that BmsnRouting protocol can tell if a BmsnPathSelectorTag value is read
 * completely. A BmsnPathSelectorTag value is read completely if the value is 0.
 * When the value is 0, BmsnRouting protocol object does not read BmsnPathSelectorTag
 * to choose exit. Instead, it chooses an exit by itself.
 *
 * Following explains some other exceptional cases.
 *
 * If BmsnPathSelectorTag is missing from a packet, BmsnRouting protocol behaves
 * as if the tag value is 0. This allow backward compatibility with packets
 * that do not have this tag added.
 *
 * \see BmsnRouting
 */
class BmsnPathSelectorTag : public Tag
{
private:
  /**
   * \brief Construct a BmsnPathSelectorTag object
   *
   * Disable this class by setting the constructor as private
   */
  BmsnPathSelectorTag(void);
  /**
   * \brief Construct a BmsnPathSelectorTag object
   *
   * \param v The value for this tag
   *
   * Disable this class by setting the constructor as private
   */
  BmsnPathSelectorTag(uint64_t v);
public:
  /// Define the four possible exit interfaces for packets to leave a node
  enum ExitDirection {North, East, South, West, None};

public:
  static TypeId GetTypeId (void);
  TypeId GetInstanceTypeId (void) const;
  /**
   * \brief Get two bits from the tag value
   *
   * \return Two bits from the left-most side of the tag value
   *
   * When all the 64 bits are shifted, an warning message is printed
   */
  uint8_t ShiftOutTwoLowestBits ();
  /**
   * \see Tag
   */
  uint32_t GetSerializedSize (void) const;
  /**
   * \see Tag
   */
  void Serialize (TagBuffer i) const;
  /**
   * \see Tag
   */
  void Deserialize (TagBuffer i);

  /**
   * \see Tag
   */
  void Print (std::ostream &os) const;
  /**
   * \brief Set the tag to a new value
   * \param v A new tag value to be set
   */
  void SetTagValue (uint64_t v);
  /**
   * \brief Get the existing tag value
   * \return The existing tag value
   */
  uint64_t GetTagValue ();
  /**
   * \brief Select an exit direction randmly from the multiple feasible exits
   *
   * \param goNorth It is true of North exit is a feasible exit
   * \param goEast It is true of East exit is a feasible exit
   * \param goSouth It is true of South exit is a feasible exit
   * \param goWest It is true of West exit is a feasible exit
   * \return From those exits that are marked true in their coresponding input arguments,
   * select an exit based upon the tag value.
   */
  ExitDirection SelectExitDirection (bool goNorth, bool goEast, bool goSouth, bool goWest);

private:
  /**
   * \brief Randomize tag value
   *
   * \return A 64 bit random number
   *
   * When the tag value is needed to be randomized, this method can
   * be called to get a 64-bit random number.
   */
  uint64_t GenerateRandom ();

  /// The tag value used to index one of the many possible out going exits
  uint64_t m_value;
  /// A uniform random number generator
  UniformVariable uniformRandom;

  friend ostream& operator<< (ostream& os, const BmsnPathSelectorTag& tag);
};
ostream& operator<< (ostream& os, const BmsnPathSelectorTag::ExitDirection& e);
ostream& operator<< (ostream& os, const BmsnPathSelectorTag& tag);

} // namespace ns3
} // namespace eecityu

#endif // #ifndef BMSN_PATH_SELECTOR_TAG_H
